﻿// -----------------------------------------------------------------------
// <copyright file="BaseMask.cs" company="Abyssalsoft">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace Gui.BaseMask
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Windows.Forms;
    using System.Xml;
    using Gui.Presentation;
    using Gui.ThemeEngine;
    using Metal.Config;

    /// <summary>
    /// The base mask that contains common methods for all the masks / containers. It also read the theme xml configuration and load objects into the mask
    /// </summary>
    public partial class BaseMask : UserControl
    {
        #region Members

        /// <summary>Stores the path to our configuration xml file</summary>
        private string strConfigFile;

        /// <summary>Stores the theme name</summary>
        private string strThemeName;

        /// <summary>Stores the name of the mask</summary>
        private string strHostName;

        /// <summary>Object to load our xml configuration file</summary>
        private XmlDocument xmlConfig = new XmlDocument();

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the BaseMask class.
        /// </summary>
        public BaseMask()
        {
            this.InitializeComponent();

            this.MouseDown += new MouseEventHandler(this.OnMouseDown);
            this.MouseMove += new MouseEventHandler(this.OnMouseMove);
            this.DoubleClick += new EventHandler(this.OnMaskDoubleClick);
            this.Load += new EventHandler(this.OnMaskLoad);
            this.Disposed += new EventHandler(this.OnMaskClose);

            //// Set the value of the double-buffering style bits to true.
            //this.DoubleBuffered = true;
            //this.UpdateStyles();

            // Fixing if the user changes DPI size:
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
        }

        #endregion

        #region Common events for all masks

        /// <summary>Occurs when the mask is loaded</summary>
        public event EventHandler MaskLoad;

        /// <summary>Occurs when the mask is closed</summary>
        public event EventHandler MaskClose;

        /// <summary>Occurs when on double click</summary>
        public event EventHandler MaskDoubleClick;

        #endregion

        #region Common properties for all masks

        /// <summary>
        /// Gets the parent form of the mask
        /// </summary>
        public Form IForm
        {
            get
            {
                return this.ParentForm;
            }
        }

        #endregion

        #region Methods

        private ThemeEngine.ControlBuilder customBuilder;

        /// <summary>
        /// Load and apply the theme
        /// </summary>
        public void ApplyTheme()
        {
            try
            {
                this.LoadThemeConfig();

                // Select the Mask node that contains the mask controls
                XmlNode mask = this.xmlConfig.SelectSingleNode("Mask");

                this.LoadMaskProperties(mask);

                // Create the controls
                customBuilder = new ThemeEngine.ControlBuilder();
                this.AddControlsRecursive(mask, this);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private void AddControlsRecursive(XmlNode xmlControl, Control parentControl)
        {
            foreach (XmlNode control in xmlControl.ChildNodes)
            {
                Control newControl = null;
                string controlType = PropertyProvider.GetValue(control, "type", string.Empty);

                if (this.CheckTopLevelControl(controlType, xmlControl))
                {
                    if (controlType == "TabControl")
                    {
                        this.BuildTabControl(control);
                    }
                    else if (controlType == "ExtendedTabControl")
                    {
                        this.BuildExtendedTabControl(control, parentControl);
                    }
                    else
                    {
                        // Create controls
                        newControl = customBuilder.CreateControl(control);
                        parentControl.Controls.Add(newControl);

                        this.AddControlsRecursive(control, newControl);
                    }
                }
            }
        }

        private bool CheckTopLevelControl(string controlType, XmlNode xmlControl)
        {
            // Ignore ContextMenu because is not a Top control, it will not be created here
            if (controlType != string.Empty && controlType != "ContextMenu")
            {
                // If we have a scrollbar in list, ignore it (it will be created when we build the list).
                if (PropertyProvider.GetValue(xmlControl, "type", string.Empty) != "List" && controlType != "Scrollbar")
                {
                    return true;
                }
            }
            return false;
        }

        private void BuildTabControl(XmlNode panel)
        {
            Gui.Controls.TabControl.MetalTabControl tabControl = (Gui.Controls.TabControl.MetalTabControl)customBuilder.CreateControl(panel);

            this.Controls.Add(tabControl);
            tabControl.BringToFront();

            string includeMask = PropertyProvider.GetValue(panel, "includeMask", "False");
            if (includeMask != "False")
            {
                // Get the mask that we must display on the first tab. The others masks will be loaded on tab click event.
                System.Reflection.Assembly assembly = System.Reflection.Assembly.Load(PropertyProvider.GetValue(panel.FirstChild, "maskNamespace", "Control not found!"));
                Type t = assembly.GetType(PropertyProvider.GetValue(panel.FirstChild, "className", "Control not found!"));
                UserControl skinableMask = (UserControl)Activator.CreateInstance(t);
                skinableMask.Dock = DockStyle.Fill;

                tabControl.TabPages[0].Controls.Add(skinableMask);
            }
        }

        /// <summary>
        /// Extended tab control contains a menu and a tab control (without tabs)
        /// </summary>
        /// <param name="panel"></param>
        private void BuildExtendedTabControl(XmlNode panel, Control parentControl)
        {
            // Create tab container (extended tab - with custom menus)
            Gui.Controls.ExtendedTabControl.MetalExtendedTab extendedTabControl = (Gui.Controls.ExtendedTabControl.MetalExtendedTab)customBuilder.CreateControl(panel);

            parentControl.Controls.Add(extendedTabControl);
            extendedTabControl.ShowPage(0);
        }

        private void LoadMaskProperties(XmlNode mask)
        {
            if (mask == null)
            {
                throw new Exception("Invalid theme. Some masks does not have a xml configuration in the theme.");
            }

            // Apply the background on the mask
            this.BackgroundImage = Image.FromFile(Paths.ThemesFolder + this.strThemeName + "\\" + PropertyProvider.GetValue(mask, "image", "no-image.png"));

            string imageLayout = PropertyProvider.GetValue(mask, "imageLayout", "None");
            if (imageLayout == "None")
            {
                this.BackgroundImageLayout = ImageLayout.None;
            }
            else if (imageLayout == "Center")
            {
                this.BackgroundImageLayout = ImageLayout.Center;
            }
            else if (imageLayout == "Stretch")
            {
                this.BackgroundImageLayout = ImageLayout.Stretch;
            }
            else if (imageLayout == "Tile")
            {
                this.BackgroundImageLayout = ImageLayout.Tile;
            }
            else if (imageLayout == "Zoom")
            {
                this.BackgroundImageLayout = ImageLayout.Zoom;
            }
        }

        private void LoadThemeConfig()
        {
            // The mask name is something like: PlaylistMask, we remove "Mask".
            int startIndex = this.ToString().LastIndexOf('.');
            string maskName = this.ToString().Substring(startIndex + 1);
            this.strHostName = maskName.Replace("Mask", string.Empty);
            this.strHostName += "_container";

            // Get theme
            this.strThemeName = Settings.Instance.GetValue("LastSettings.Theme", "BlackMetal");

            // Load theme configuration from xml
            try
            {
                this.strConfigFile = Paths.ThemesFolder + this.strThemeName + "\\" + this.strHostName + ".xml";
                this.xmlConfig.Load(this.strConfigFile);
            }
            catch
            {
                this.xmlConfig.LoadXml("<Form></Form>");
            }
        }

        /// <summary>
        /// Find a control by string (so we don't give a shit about where it is)
        /// </summary>
        /// <param name="controlName">The control name</param>
        /// <returns>Returns the control, or null if it does not exist on the mask</returns>
        public Control GetControl(string controlName)
        {
            // Control.Find method returns an array of controls. But we have unique names, so we return always the first control found.
            try
            {
                return (this.Controls.Find(controlName, true))[0];
            }
            catch
            {
                return null;
            }
        }

        #endregion

        #region Private events

        /// <summary>
        /// Occurs when the mask is loaded
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Event args</param>
        private void OnMaskLoad(object sender, EventArgs e)
        {
            this.MaskLoad(sender, e);
        }

        /// <summary>
        /// Occurs when the mask is closed
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Event args</param>
        private void OnMaskClose(object sender, EventArgs e)
        {
            this.MaskClose(sender, e);
        }

        /// <summary>
        /// Occurs on mask double click
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Event args</param>
        private void OnMaskDoubleClick(object sender, EventArgs e)
        {
            if (this.MaskDoubleClick != null)
            {
                this.MaskDoubleClick(sender, e);
            }
        }

        /// <summary>
        /// Start moving the form
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Mouse Event args</param>
        private void OnMouseDown(object sender, MouseEventArgs e)
        {
            Gui.BaseForm.FormMove.Instance.Start(e, this.ParentForm);
        }

        /// <summary>
        /// Move the form
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Mouse event args</param>
        private void OnMouseMove(object sender, MouseEventArgs e)
        {
            Gui.BaseForm.FormMove.Instance.Move(e, this.ParentForm);
        }

        /// <summary>
        /// Stop moving the form
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Mouse event args</param>
        private void BaseMask_MouseUp(object sender, MouseEventArgs e)
        {
            Gui.BaseForm.FormMove.Instance.Stop();
        }

        #endregion
    }
}
